"""
音频缓冲和预加载策略管理服务
"""

import asyncio
import time
from typing import Dict, List, Any, Optional, Callable, Deque
from dataclasses import dataclass, field
from enum import Enum
from collections import deque
import threading
import struct
import io

from ...core.exceptions import BusinessLogicError, ValidationError
from ...core.logging import get_logger
from ...core.config import settings
from ...services.cache import cache_service

logger = get_logger(__name__)


class BufferState(Enum):
    """缓冲区状态"""
    EMPTY = "empty"
    FILLING = "filling"
    READY = "ready"
    UNDERRUN = "underrun"
    OVERFLOW = "overflow"


class PreloadStrategy(Enum):
    """预加载策略"""
    CONSERVATIVE = "conservative"  # 保守策略
    AGGRESSIVE = "aggressive"     # 激进策略
    ADAPTIVE = "adaptive"         # 自适应策略


@dataclass
class BufferConfig:
    """缓冲配置"""
    min_buffer_size: int = 5      # 最小缓冲块数
    max_buffer_size: int = 30     # 最大缓冲块数
    target_buffer_size: int = 15   # 目标缓冲块数
    buffer_underrun_threshold: float = 0.2  # 缓冲区耗尽阈值
    buffer_overflow_threshold: float = 0.8   # 缓冲区溢出阈值
    preload_ahead: int = 3         # 预加载块数
    chunk_size: int = 8192        # 块大小(字节)
    max_chunk_duration: float = 5.0  # 最大块时长(秒)
    preload_strategy: PreloadStrategy = PreloadStrategy.ADAPTIVE


@dataclass
class BufferStats:
    """缓冲统计"""
    total_chunks: int = 0
    consumed_chunks: int = 0
    dropped_chunks: int = 0
    underruns: int = 0
    overflows: int = 0
    refill_count: int = 0
    avg_fill_ratio: float = 0.0
    buffer_health_score: float = 0.0
    last_refill_time: float = 0.0


@dataclass
class AudioChunk:
    """音频块"""
    sequence_number: int
    data: bytes
    duration: float
    timestamp: float = field(default_factory=time.time)
    checksum: str = ""
    metadata: Dict[str, Any] = field(default_factory=dict)
    
    def __post_init__(self):
        if not self.checksum:
            import hashlib
            self.checksum = hashlib.md5(self.data).hexdigest()


class SmartBuffer:
    """智能缓冲区"""
    
    def __init__(self, config: BufferConfig, buffer_id: str):
        self.config = config
        self.buffer_id = buffer_id
        
        # 缓冲存储
        self._buffer: Deque[AudioChunk] = deque(maxlen=config.max_buffer_size)
        self._state = BufferState.EMPTY
        self._stats = BufferStats()
        
        # 控制标志
        self._filling = False
        self._paused = False
        self._closed = False
        
        # 回调函数
        self._state_change_callbacks: List[Callable[[BufferState, BufferState], None]] = []
        self._buffer_level_callbacks: List[Callable[[float], None]] = []
        self._chunk_ready_callbacks: List[Callable[[AudioChunk], None]] = []
        
        # 预加载策略
        self._preload_strategy = config.preload_strategy
        self._network_quality = 1.0  # 网络质量评分 0-1
        self._last_fill_time = 0.0
        
        # 线程锁
        self._lock = asyncio.Lock()
        
        logger.info(f"SmartBuffer {buffer_id} initialized with config: {config}")
    
    async def add_chunk(self, chunk: AudioChunk) -> bool:
        """添加音频块到缓冲区"""
        async with self._lock:
            if self._closed:
                return False
            
            # 检查缓冲区是否已满
            if len(self._buffer) >= self.config.max_buffer_size:
                self._stats.dropped_chunks += 1
                self._state = BufferState.OVERFLOW
                await self._notify_state_change()
                return False
            
            # 验证块完整性
            if not await self._validate_chunk(chunk):
                logger.warning(f"Invalid chunk {chunk.sequence_number}, dropping")
                return False
            
            # 添加到缓冲区
            self._buffer.append(chunk)
            self._stats.total_chunks += 1
            
            # 更新状态
            await self._update_state()
            
            # 通知块就绪
            await self._notify_chunk_ready(chunk)
            
            logger.debug(f"Added chunk {chunk.sequence_number} to buffer {self.buffer_id}")
            return True
    
    async def get_chunk(self, timeout: float = 1.0) -> Optional[AudioChunk]:
        """从缓冲区获取音频块"""
        if self._closed:
            return None
        
        start_time = time.time()
        
        while True:
            async with self._lock:
                if self._buffer:
                    chunk = self._buffer.popleft()
                    self._stats.consumed_chunks += 1
                    
                    # 更新状态
                    await self._update_state()
                    
                    logger.debug(f"Retrieved chunk {chunk.sequence_number} from buffer {self.buffer_id}")
                    return chunk
                
                # 检查是否超时
                if time.time() - start_time > timeout:
                    logger.warning(f"Buffer {self.buffer_id} underrun timeout")
                    self._state = BufferState.UNDERRUN
                    self._stats.underruns += 1
                    await self._notify_state_change()
                    return None
                
                # 如果没有数据且未关闭，等待一小段时间
                if not self._closed:
                    await asyncio.sleep(0.01)
                else:
                    return None
    
    async def peek_chunks(self, count: int = 1) -> List[AudioChunk]:
        """预览缓冲区中的块（不移除）"""
        async with self._lock:
            if len(self._buffer) == 0:
                return []
            
            return list(self._buffer)[:count]
    
    async def get_chunks_batch(self, count: int, timeout: float = 1.0) -> List[AudioChunk]:
        """批量获取音频块"""
        chunks = []
        remaining_time = timeout
        start_time = time.time()
        
        for _ in range(count):
            elapsed = time.time() - start_time
            if elapsed >= timeout:
                break
            
            chunk_timeout = timeout - elapsed
            chunk = await self.get_chunk(chunk_timeout)
            
            if chunk:
                chunks.append(chunk)
            else:
                break
        
        return chunks
    
    async def clear(self):
        """清空缓冲区"""
        async with self._lock:
            self._buffer.clear()
            self._state = BufferState.EMPTY
            await self._notify_state_change()
            
            logger.info(f"Cleared buffer {self.buffer_id}")
    
    async def pause(self):
        """暂停缓冲"""
        self._paused = True
        logger.info(f"Paused buffer {self.buffer_id}")
    
    async def resume(self):
        """恢复缓冲"""
        self._paused = False
        logger.info(f"Resumed buffer {self.buffer_id}")
    
    async def close(self):
        """关闭缓冲区"""
        self._closed = True
        await self.clear()
        logger.info(f"Closed buffer {self.buffer_id}")
    
    def is_ready(self) -> bool:
        """检查缓冲区是否就绪"""
        return (
            self._state == BufferState.READY and 
            len(self._buffer) >= self.config.min_buffer_size
        )
    
    def is_empty(self) -> bool:
        """检查缓冲区是否为空"""
        return len(self._buffer) == 0
    
    def is_full(self) -> bool:
        """检查缓冲区是否已满"""
        return len(self._buffer) >= self.config.max_buffer_size
    
    def get_fill_ratio(self) -> float:
        """获取填充比例"""
        if self.config.max_buffer_size == 0:
            return 0.0
        return len(self._buffer) / self.config.max_buffer_size
    
    def get_state(self) -> BufferState:
        """获取当前状态"""
        return self._state
    
    def get_stats(self) -> BufferStats:
        """获取统计信息"""
        self._stats.avg_fill_ratio = self.get_fill_ratio()
        self._stats.buffer_health_score = self._calculate_health_score()
        
        return BufferStats(
            total_chunks=self._stats.total_chunks,
            consumed_chunks=self._stats.consumed_chunks,
            dropped_chunks=self._stats.dropped_chunks,
            underruns=self._stats.underruns,
            overflows=self._stats.overflows,
            refill_count=self._stats.refill_count,
            avg_fill_ratio=self._stats.avg_fill_ratio,
            buffer_health_score=self._stats.buffer_health_score,
            last_refill_time=self._stats.last_refill_time
        )
    
    def set_network_quality(self, quality: float):
        """设置网络质量评分"""
        self._network_quality = max(0.0, min(1.0, quality))
        logger.debug(f"Network quality set to {self._network_quality}")
    
    def set_preload_strategy(self, strategy: PreloadStrategy):
        """设置预加载策略"""
        self._preload_strategy = strategy
        logger.info(f"Preload strategy changed to {strategy.value}")
    
    def add_state_change_callback(self, callback: Callable[[BufferState, BufferState], None]):
        """添加状态变化回调"""
        self._state_change_callbacks.append(callback)
    
    def add_buffer_level_callback(self, callback: Callable[[float], None]):
        """添加缓冲区水平回调"""
        self._buffer_level_callbacks.append(callback)
    
    def add_chunk_ready_callback(self, callback: Callable[[AudioChunk], None]):
        """添加块就绪回调"""
        self._chunk_ready_callbacks.append(callback)
    
    async def _validate_chunk(self, chunk: AudioChunk) -> bool:
        """验证音频块"""
        if not chunk.data:
            return False
        
        # 验证块大小
        if len(chunk.data) > self.config.chunk_size * 2:  # 允许一定误差
            return False
        
        # 验证持续时间
        if chunk.duration > self.config.max_chunk_duration:
            return False
        
        # 验证校验和
        import hashlib
        calculated_checksum = hashlib.md5(chunk.data).hexdigest()
        if calculated_checksum != chunk.checksum:
            return False
        
        return True
    
    async def _update_state(self):
        """更新缓冲区状态"""
        old_state = self._state
        
        # 计算填充比例
        fill_ratio = self.get_fill_ratio()
        
        # 确定状态
        if len(self._buffer) == 0:
            self._state = BufferState.EMPTY
        elif fill_ratio < self.config.buffer_underrun_threshold:
            self._state = BufferState.UNDERRUN
            self._stats.underruns += 1
        elif fill_ratio > self.config.buffer_overflow_threshold:
            self._state = BufferState.OVERFLOW
            self._stats.overflows += 1
        elif len(self._buffer) < self.config.target_buffer_size:
            self._state = BufferState.FILLING
        else:
            self._state = BufferState.READY
        
        # 通知状态变化
        if old_state != self._state:
            await self._notify_state_change()
        
        # 通知缓冲区水平变化
        await self._notify_buffer_level(fill_ratio)
    
    async def _notify_state_change(self):
        """通知状态变化"""
        for callback in self._state_change_callbacks:
            try:
                if asyncio.iscoroutinefunction(callback):
                    await callback(self._state, self._state)
                else:
                    callback(self._state, self._state)
            except Exception as e:
                logger.error(f"State change callback error: {e}")
    
    async def _notify_buffer_level(self, fill_ratio: float):
        """通知缓冲区水平变化"""
        for callback in self._buffer_level_callbacks:
            try:
                if asyncio.iscoroutinefunction(callback):
                    await callback(fill_ratio)
                else:
                    callback(fill_ratio)
            except Exception as e:
                logger.error(f"Buffer level callback error: {e}")
    
    async def _notify_chunk_ready(self, chunk: AudioChunk):
        """通知块就绪"""
        for callback in self._chunk_ready_callbacks:
            try:
                if asyncio.iscoroutinefunction(callback):
                    await callback(chunk)
                else:
                    callback(chunk)
            except Exception as e:
                logger.error(f"Chunk ready callback error: {e}")
    
    def _calculate_health_score(self) -> float:
        """计算缓冲区健康评分"""
        score = 0.0
        
        # 填充率评分 (40%)
        fill_score = self.get_fill_ratio()
        score += fill_score * 0.4
        
        # 稳定性评分 (30%) - 基于错误率
        total_operations = self._stats.total_chunks + self._stats.underruns + self._stats.overflows
        if total_operations > 0:
            error_rate = (self._stats.dropped_chunks + self._stats.underruns + self._stats.overflows) / total_operations
            stability_score = max(0.0, 1.0 - error_rate)
            score += stability_score * 0.3
        else:
            score += 0.3
        
        # 网络质量评分 (30%)
        score += self._network_quality * 0.3
        
        return min(1.0, score)


class BufferManager:
    """缓冲管理器"""
    
    def __init__(self):
        self.buffers: Dict[str, SmartBuffer] = {}
        self.default_config = BufferConfig()
        
        # 统计信息
        self._global_stats = {
            "total_buffers": 0,
            "active_buffers": 0,
            "total_chunks_processed": 0,
            "total_dropped_chunks": 0,
            "average_buffer_health": 0.0
        }
        
        logger.info("BufferManager initialized")
    
    async def create_buffer(
        self,
        buffer_id: str,
        config: Optional[BufferConfig] = None
    ) -> SmartBuffer:
        """创建缓冲区"""
        if buffer_id in self.buffers:
            raise ValidationError(f"Buffer {buffer_id} already exists")
        
        buffer_config = config or self.default_config
        buffer = SmartBuffer(buffer_config, buffer_id)
        
        # 设置回调
        buffer.add_state_change_callback(self._on_buffer_state_change)
        buffer.add_buffer_level_callback(self._on_buffer_level_change)
        
        self.buffers[buffer_id] = buffer
        self._global_stats["total_buffers"] += 1
        self._global_stats["active_buffers"] += 1
        
        logger.info(f"Created buffer {buffer_id}")
        return buffer
    
    async def get_buffer(self, buffer_id: str) -> Optional[SmartBuffer]:
        """获取缓冲区"""
        return self.buffers.get(buffer_id)
    
    async def remove_buffer(self, buffer_id: str) -> bool:
        """移除缓冲区"""
        if buffer_id not in self.buffers:
            return False
        
        buffer = self.buffers[buffer_id]
        await buffer.close()
        
        del self.buffers[buffer_id]
        self._global_stats["active_buffers"] -= 1
        
        logger.info(f"Removed buffer {buffer_id}")
        return True
    
    async def cleanup_inactive_buffers(self, max_idle_time: float = 300.0) -> int:
        """清理非活跃缓冲区"""
        current_time = time.time()
        cleaned_count = 0
        
        buffers_to_remove = []
        
        for buffer_id, buffer in self.buffers.items():
            stats = buffer.get_stats()
            
            # 检查是否长时间无活动
            if (current_time - stats.last_refill_time > max_idle_time and 
                buffer.is_empty()):
                buffers_to_remove.append(buffer_id)
        
        # 清理缓冲区
        for buffer_id in buffers_to_remove:
            await self.remove_buffer(buffer_id)
            cleaned_count += 1
        
        if cleaned_count > 0:
            logger.info(f"Cleaned up {cleaned_count} inactive buffers")
        
        return cleaned_count
    
    async def get_global_stats(self) -> Dict[str, Any]:
        """获取全局统计信息"""
        total_health = 0.0
        total_chunks = 0
        total_dropped = 0
        
        for buffer in self.buffers.values():
            stats = buffer.get_stats()
            total_health += stats.buffer_health_score
            total_chunks += stats.total_chunks
            total_dropped += stats.dropped_chunks
        
        active_count = len(self.buffers)
        avg_health = total_health / active_count if active_count > 0 else 0.0
        
        self._global_stats.update({
            "active_buffers": active_count,
            "total_chunks_processed": total_chunks,
            "total_dropped_chunks": total_dropped,
            "average_buffer_health": avg_health
        })
        
        return dict(self._global_stats)
    
    async def optimize_buffer_configs(self):
        """优化缓冲区配置"""
        for buffer_id, buffer in self.buffers.items():
            stats = buffer.get_stats()
            
            # 根据统计信息调整配置
            if stats.underruns > 5:  # 频繁耗尽
                # 增加目标缓冲区大小
                new_target = min(buffer.config.max_buffer_size, 
                                buffer.config.target_buffer_size + 2)
                if new_target != buffer.config.target_buffer_size:
                    buffer.config.target_buffer_size = new_target
                    logger.info(f"Increased target buffer size for {buffer_id} to {new_target}")
            
            elif stats.overflows > 3:  # 频繁溢出
                # 减少最大缓冲区大小
                new_max = max(buffer.config.min_buffer_size * 2,
                             buffer.config.max_buffer_size - 5)
                if new_max != buffer.config.max_buffer_size:
                    buffer.config.max_buffer_size = new_max
                    logger.info(f"Reduced max buffer size for {buffer_id} to {new_max}")
    
    async def _on_buffer_state_change(self, old_state: BufferState, new_state: BufferState):
        """缓冲区状态变化处理"""
        logger.debug(f"Buffer state change: {old_state.value} -> {new_state.value}")
        
        # 可以在这里添加自动处理逻辑
        if new_state == BufferState.UNDERRUN:
            # 触发重填逻辑
            pass
        elif new_state == BufferState.OVERFLOW:
            # 触发清理逻辑
            pass
    
    async def _on_buffer_level_change(self, fill_ratio: float):
        """缓冲区水平变化处理"""
        # 可以在这里添加预加载逻辑
        if fill_ratio < 0.3:
            # 缓冲区较低，可能需要加速预加载
            pass


# 全局缓冲管理器实例
buffer_manager = BufferManager()
